package com.nosql.db.core.storage;

import com.nosql.db.core.modul.Document;
import com.nosql.common.util.SerializationUtil;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class SSTable {
    private final Path filepath;
    private Map<String, Long> index = new ConcurrentHashMap<>();
    private int level;
    private long size;

    public SSTable(Path filepath, int level) {
        this.filepath = filepath;
        this.level = level;
    }

    public Path getFilepath() {
        return filepath;
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public void write(MemTable memTable) throws IOException {
        try (BufferedWriter writer = Files.newBufferedWriter(filepath)) {
            Map<String, Long> indexMap = new HashMap<>();
            long offset = 0;

            // 写入数据段
            writer.write("#DATA_START\n");
            offset += "#DATA_START\n".getBytes().length;

            for (Document doc : memTable.values()) {
                String line = convertToTxt(doc) + "\n";
                byte[] lineBytes = line.getBytes(StandardCharsets.UTF_8);
                writer.write(line);
                indexMap.put(doc.getId(), offset);
                offset += lineBytes.length;
            }

            // 写入索引段
            writer.write("#INDEX_START\n");
            for (Map.Entry<String, Long> entry : indexMap.entrySet()) {
                String indexLine = entry.getKey() + ":" + entry.getValue() + "\n";
                writer.write(indexLine);
            }
            writer.write("#INDEX_END\n");
            this.index = new ConcurrentHashMap<>(indexMap);
        }
    }

    public Document get(String id) throws IOException {
        try (BufferedReader reader = Files.newBufferedReader(filepath)) {
            String line;
            boolean inDataSection = false;
            while ((line = reader.readLine()) != null) {
                if (line.equals("#DATA_START")) {
                    inDataSection = true;
                    continue;
                }
                if (line.equals("#INDEX_START")) break;

                if (inDataSection) {
                    Document doc = parseTxtLine(line);
                    if (doc.getId().equals(id)) {
                        return doc;
                    }
                }
            }
        }
        return null;
    }

    public void writeWithIndex(MemTable memTable) throws IOException {
        try (BufferedWriter writer = Files.newBufferedWriter(filepath)) {
            long offset = 0;
            Map<String, Long> indexMap = new HashMap<>();

            // 写入DATA_START标记并计算其字节长度
            String dataStart = "#DATA_START\n";
            writer.write(dataStart);
            offset += dataStart.getBytes(StandardCharsets.UTF_8).length;

            // 写入数据行
            for (Document doc : memTable.values()) {
                String dataLine = convertToTxt(doc) + "\n";
                byte[] lineBytes = dataLine.getBytes(StandardCharsets.UTF_8);
                indexMap.put(doc.getId(), offset); // 记录当前偏移量
                writer.write(dataLine);
                offset += lineBytes.length; // 累加字节数
            }

            // 写入INDEX_START标记
            String indexStart = "#INDEX_START\n";
            writer.write(indexStart);
            offset += indexStart.getBytes(StandardCharsets.UTF_8).length;

            // 写入索引条目
            for (Map.Entry<String, Long> entry : indexMap.entrySet()) {
                String indexLine = entry.getKey() + ":" + entry.getValue() + "\n";
                byte[] indexBytes = indexLine.getBytes(StandardCharsets.UTF_8);
                writer.write(indexLine);
                offset += indexBytes.length;
            }
            this.index = new ConcurrentHashMap<>(indexMap);
            System.out.println("[SSTable] 加载索引条目数: " + index.size());
            writer.write("#INDEX_END\n");
            this.size = Files.size(filepath);
        }
    }


    // 序列化时增加转义 (SSTable.java)
    private String convertToTxt(Document doc) {
        // 处理墓碑文档
        if (doc.isTombstone()) {
            return String.format("TOMBSTONE|ID=%s|COLLECTION=%s|TIMESTAMP=%d",
                    doc.getId(), doc.getCollection(), doc.getTimestamp());
        }
        // 添加版本号字段
        Map<String, Object> dataWithVersion = new HashMap<>(doc.getData());
        dataWithVersion.put("_version", doc.getTimestamp());
        String escapedData = doc.getData().entrySet().stream()
                .map(e -> {
                    String key = e.getKey()
                            .replace("=", "\\=")
                            .replace(",", "\\,");
                    String value = e.getValue().toString()
                            .replace("=", "\\=")
                            .replace(",", "\\,");
                    return key + "=" + value;
                })
                .collect(Collectors.joining(","));
        if (doc.isTombstone()) {
            return String.format("TOMBSTONE|ID=%s|COLLECTION=%s|TIMESTAMP=%d",
                    doc.getId(), doc.getCollection(), doc.getTimestamp());
        } else {
            return String.format(
                    "ID=%s|COLLECTION=%s|DATA=%s|TIMESTAMP=%d",
                    doc.getId(),
                    doc.getCollection(),
                    escapedData,
                    doc.getTimestamp()
            );
        }

    }

    // 新增辅助方法
    public void loadIndex() throws IOException {
        try (RandomAccessFile raf = new RandomAccessFile(filepath.toFile(), "r")) {
            int indexLength = raf.readInt();
            byte[] indexData = new byte[indexLength];
            raf.readFully(indexData);
            this.index = SerializationUtil.deserialize(indexData, ConcurrentHashMap.class);
        } catch (ClassNotFoundException e) {
            throw new IOException("Index deserialization failed", e);
        }
    }


    // 新增在SSTable类中的方法
    private Document parseTxtLine(String line) {
        String[] parts = line.split("\\|");
        Map<String, String> fields = new HashMap<>();
        // 处理墓碑文档
        if (line.startsWith("TOMBSTONE|")) {
            for (String part : parts) {
                String[] kv = part.split("=", 2);
                if (kv.length == 2) {
                    fields.put(kv[0], kv[1]);
                }
            }

            Document doc = new Document(
                    fields.get("ID"),
                    fields.get("COLLECTION"),
                    new HashMap<>(),
                    Long.parseLong(fields.get("TIMESTAMP"))
            );
            doc.markAsTombstone();
            return doc;
        }

        for (String part : parts) {
            String[] kv = part.split("=", 2);
            if (kv.length == 2) {
                fields.put(kv[0], kv[1]);
            }
        }

        // 解析DATA字段并处理转义字符
        Map<String, Object> data = new HashMap<>();
        String escapedData = fields.get("DATA");
        if (escapedData != null) {
            String[] entries = escapedData.split("(?<!\\\\),");
            for (String entry : entries) {
                String[] kv = entry.split("(?<!\\\\)=", 2);
                if (kv.length == 2) {
                    String key = kv[0].replace("\\=", "=").replace("\\,", ",");
                    String value = kv[1].replace("\\=", "=").replace("\\,", ",");
                    data.put(key, value);
                }
            }
        }

        return new Document(
                fields.get("ID"),
                fields.get("COLLECTION"),
                data,
                Long.parseLong(fields.get("TIMESTAMP"))
        );
    }


    public long getSize() {
        return size;
    }

}

